# coding:utf-8
import logging
import os
import time

import allure
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

from common.log import Log
from config import report_path

# logging.setLoggerClass(Log)
success = "SUCCESS   "
fail = "FAIL      "
warning = "WARNING   "
error = "ERROR     "
Log()
el = None


class Browser_engine(object):
    """浏览器引擎"""

    @staticmethod
    def get_browser(browsertype="chrome", op=None):
        t1 = time.time()
        try:
            if browsertype == "ie":
                driver = webdriver.Ie()
            elif browsertype == "firefox":
                driver = webdriver.Firefox()
            else:

                # options = webdriver.ChromeOptions()
                # options.add_argument('--headless')
                # driver = webdriver.Chrome(chrome_options=options)

                driver = webdriver.Chrome(options=op)

            logging.info(
                "{0} 新建浏览器: {1}, 用时 {2:.2f} 秒.".format(success, browsertype, time.time() - t1)
            )
            return driver
        except Exception:

            raise NameError(
                "未发现 {0} 浏览器,你可以输入 'ie','chrome','firefox'.".format(browsertype)
            )


class pyselenium(Browser_engine):
    # el = None
    def __init__(self, driver):
        self.driver = driver
        self.el = None
        # self.driver = webdriver.Chrome()  # 调试模式

    def open(self, url):
        """打开网址"""
        t1 = time.time()
        try:
            self.driver.get(url)
            logging.info(
                "{0} 成功打开链接：{1}，用时 {2:.2f} 秒.".format(success, url, time.time() - t1)
            )
            return self
        except Exception:
            self.take_screenshot()
            logging.info(
                "{0} 打开链接失败.".format(fail)
            )
            raise

    def element_wait(self, css, sec=30):

        t1 = time.time()
        messages = '{0}秒内，未能找到元素：{1} '.format(sec, css)
        try:
            WebDriverWait(self.driver, sec, 1).until(
                EC.presence_of_all_elements_located(css),
                messages
            )

            logging.debug("{0} 等待{1}元素可见, 用时{2:.2f}秒.".format(success, css, time.time() - t1))

        except:
            logging.error("{0} 等待{1}元素可见失败, 用时{2:.2f}秒.".format(fail, css, time.time() - t1))
            raise

    # ement

    def get_element(self, css):
        """获取元素"""

        t1 = time.time()
        logging.info("{0} 查找元素：{1}, 用时{2:.2f}秒.".format(success, css, time.time() - t1))
        try:
            ele = self.driver.find_element(*css)

        except:
            self.take_screenshot()
            logging.error("{0} 查找元素{1}失败！用时{2:.2f}秒.".format(fail, css, time.time() - t1))
            raise

        else:
            return ele

    def get_elements(self, css):
        """
        Judge element positioning way, and returns the element.
        批量获取元素。
        Usage:
        driver.get_elements('id->kw')
        """

        t1 = time.time()
        logging.info("{0} 查找元素：{1}, 用时{2:.2f}秒.".format(success, css, time.time() - t1))
        try:
            ele = self.driver.find_elements(*css)

        except:
            self.take_screenshot()
            logging.error("{0} 查找元素{1}失败！用时{2:.2f}秒.".format(fail, css, time.time() - t1))
            raise

        else:
            return ele

    def input_and_enter(self, css, text, sec=1):
        """输入并敲击回车"""
        #
        t1 = time.time()
        try:
            self.element_wait(css)

            self.el = self.get_element(css)
            self.el.send_keys(text)
            time.sleep(sec)
            self.el.send_keys(Keys.ENTER)
            logging.info(
                "{0} 元素：{1}，内容：‘{2}’输入成功， 用时 {3:.2f} 秒.".format(success, css, text, time.time() - t1)
            )
        except Exception:
            self.take_screenshot()
            logging.info(
                "{0} 元素：{1}，内容：‘{2}’输入失败， 用时 {3:.2f} 秒.".format(fail, css, text, time.time() - t1)
            )
            raise

    def Ctrl_A_input(self, css, text):

        t1 = time.time()
        try:
            self.element_wait(css)

            self.el = self.get_element(css)
            self.el.send_keys(Keys.CONTROL, "a")
            self.el.send_keys(text)
            logging.info(
                "{0} 元素：{1}，内容：‘{2}’输入成功， 用时 {3:.2f} 秒.".format(success, css, text, time.time() - t1)
            )

        except Exception:

            logging.info(
                "{0} 元素：{1}，内容：‘{2}’输入失败， 用时 {3:.2f} 秒.".format(fail, css, text, time.time() - t1)
            )
            self.take_screenshot()
            raise

    def clear_input_enter(self, css, text):

        """清除默认内容，并输入新内容"""

        t1 = time.time()
        try:
            self.element_wait(css)
            self.el = self.get_element(css)
            self.el.clear()

        except Exception:

            logging.error("{0} 无法清除元素: <{1}> 输入: {2}, 用时 {3:.2f} 秒.".format(fail, css, text, time.time() - t1))
            self.take_screenshot()
            raise

    # def Enter(self,css):
    #
    #     """清除默认内容，并输入新内容"""
    #     t1 = time.time()
    #     try:
    #         self.element_wait(css)
    #         el = self.get_element(css)
    #         el.send_keys(Keys.ENTER)
    #         logging.info()("{0} 清除元素: <{1}> 输入: {2}, 用时 {3:.2f} 秒.".format(success, css, time.time() - t1))
    #     except Exception:
    #         logging.info()("{0} 无法清除元素: <{1}> 输入: {2}, 用时 {3:.2f} 秒.".format(fail, css, time.time() - t1))
    #         raise

    def input(self, css, text):
        """输入"""

        t1 = time.time()
        try:
            self.element_wait(css)

            self.el = self.get_element(css)
            self.el.send_keys(text)
            logging.info(
                "{0} 元素：{1}，内容：‘{2}’输入成功， 用时 {3:.2f} 秒.".format(success, css, text, time.time() - t1)
            )
            return self
        except Exception:

            logging.error(
                "{0} 元素：{1}，内容：‘{2}’输入失败， 用时 {3:.2f} 秒.".format(fail, css, text, time.time() - t1)
            )
            self.take_screenshot()
            raise

    def quit(self):
        """关闭浏览器"""
        t1 = time.time()
        self.driver.quit()
        logging.info(
            "{0} 退出浏览器并清除临时文件， 用时 {1:.2f} 秒.".format(success, time.time() - t1)
        )
        return self

    def F5(self):
        """刷新"""
        t1 = time.time()
        self.driver.refresh()
        logging.info(
            "{0} 刷新页面，用时{1:.2f}秒.".format(success, time.time() - t1)
        )
        return self

    def take_screenshot(self):
        """截图"""
        t1 = time.time()
        date = time.strftime('%Y-%m-%d')
        file_path = report_path + date
        image_path = file_path + "/image/"
        isExists = os.path.exists(file_path)
        isExists2 = os.path.exists(image_path)
        if not isExists:
            os.mkdir(file_path)
        if not isExists2:
            os.mkdir(image_path)
        date = time.strftime('%Y%m%d%H%M%S', time.localtime())
        screenname = image_path + date + ".png"
        try:
            picture_url = self.driver.get_screenshot_as_png()
            picture_path = self.driver.get_screenshot_as_file(screenname)
            if picture_path:
                allure.attach(picture_url, date)
                print('screenshot:  {0}.png'.format(date))
                logging.info(
                    "{0} 截图保存成功，地址为{1}， 用时 {2:.2f} 秒.".format(success, image_path, time.time() - t1)
                )
            else:
                logging.error("{0} 截图保存失败.".format(warning))
        except Exception:
            logging.error("截图失败!")
            raise AttributeError(
                "截图失败"
            )

    def get_attribute(self, css, name):
        """

        :param css:
        :param name: 属性名
        :return:
        """

        t1 = time.time()
        try:
            self.element_wait(css)

            attribute = self.get_element(css).get_attribute(name)
            logging.info(
                "{0} 获取元素{1}的{2}属性为{3}， 用时 {4:.2f} 秒.".format(success, css, name, attribute, time.time() - t1)
            )
            return attribute
        except Exception:
            logging.error(
                "{0} 未能点击元素{1}.".format(fail, css)
            )
            raise

    def click(self, css):
        """点击"""

        t1 = time.time()
        try:
            self.element_wait(css)
            self.get_element(css).click()

            logging.info(
                "{0} 点击元素：{1}， 用时 {2:.2f} 秒.".format(success, css, time.time() - t1)
            )
            return self
        except Exception:
            logging.error(
                "{0} 未能点击元素{1}.".format(fail, css)
            )
            raise

    def clicks(self, css, num):
        """
        点击元素组中的元素
        :param css:
        :param num:
        :return:
        """

        t1 = time.time()
        try:

            self.el = self.get_elements(css)
            self.el[num].click()
            logging.info(
                "{0} 点击第{1}元素：{2}， 用时 {3:.2f} 秒.".format(success, num + 1, css, time.time() - t1)
            )
        except Exception:
            logging.error(
                "{0} 未能点击元素{1}.".format(fail, css)
            )
            raise

    def movetoelement(self, css):
        """悬停元素"""

        t1 = time.time()
        try:
            self.element_wait(css)

            self.el = self.get_element(css)
            ActionChains(self.driver).move_to_element(el).perform()
            logging.info(
                "{0} 移动到元素: <{1}>, 用时 {2:.2f} 秒.".format(success, css, time.time() - t1)
            )
            return self
        except Exception:
            logging.error(
                "{0} 无法移动到元素: <{1}>, 用时 {2:.2f} 秒.".format(fail, css, time.time() - t1)
            )
            raise

    def wait(self, secs=5):
        """隐性等待"""
        self.driver.implicitly_wait(secs)
        logging.info(
            "{0} 等待 {1:.2f} 秒钟".format(success, secs)
        )

    # @staticmethod
    def sleep(self,secs=5):
        """强制等待"""
        time.sleep(secs)
        logging.info(
            "{0} 等待 {1:.2f} 秒钟".format(success, secs)
        )
        return self

    def max_window(self):
        """最大化浏览器"""
        t1 = time.time()
        self.driver.maximize_window()
        logging.info(
            "{0} 浏览器窗口最大化, 用时 {1:.2f} 秒.".format(success, time.time() - t1)
        )

    def get_text(self, css):
        """获取元素的文本值"""

        t1 = time.time()
        try:
            self.element_wait(css)

            self.el = self.get_element(css)
            text = self.el.text
            # logging.info()(
            #     "{0} 获取元素文本 元素: <{1}> 文本内容：<{2}>, 用时 {3:.2f} 秒.".format(success, css, text, time.time() - t1),
            #     level=1
            # )
            logging.info(
                "{0} 获取元素文本 元素: <{1}> , 用时 {2:.2f} 秒.".format(success, css, time.time() - t1),
            )

            return text
        except Exception:
            logging.error(
                "{0} 无法获取元素文本 元素: <{1}>, 用时 {2:.2f} 秒.".format(fail, css, time.time() - t1)
            )
            self.take_screenshot()
            raise

    def text_assert(self, text, css, sec=15, asserttype="in"):
        """文本断言"""
        t1 = time.time()
        try:
            self.element_wait(css, sec)
            page_text = self.get_text(css)
            if asserttype == 'in':
                assert text in page_text
                logging.info(
                    "{0} 断言类型：{1}  通过  元素: <{2}> , 用时 {3:.2f} 秒.".format(success, asserttype, css,
                                                                         time.time() - t1)
                )
            elif asserttype == "not in":
                if page_text != '':
                    assert text not in page_text
                    logging.info(
                        "{0} 断言类型：{1}  通过  元素: <{2}> , 用时 {3:.2f} 秒.".format(success, asserttype, css,
                                                                             time.time() - t1)
                    )
                else:
                    logging.info("{0} 断言元素文本内容为空， 用时 {1:.2f} 秒.".format(error, time.time() - t1))
            else:
                logging.error(
                    "断言类型错误，请输入'in'或者'not in'."
                )
        except AssertionError:
            logging.error(
                "{0} 断言类型：{1}  未通过  元素: <{2}> 断言文本：<{3}>, 用时 {4:.2f} 秒.".format(fail, asserttype, css, text,
                                                                                time.time() - t1)
            )
            self.take_screenshot()
            raise

    def __isElementPresent(self, css, sec=15):
        from selenium.common.exceptions import TimeoutException
        try:
            self.element_wait(css, sec)
        except TimeoutException:
            return False
        else:
            return True

    def ele_assert(self, css, sec=30):
        t1 = time.time()
        try:
            assert self.__isElementPresent(css, sec=sec)
            logging.info("{0} 断言通过  元素: <{1}> , 用时 {2:.2f} 秒.".format(success, css, time.time() - t1))
        except AssertionError:
            logging.error("{0} 断言未通过  元素: <{1}> , 用时 {2:.2f} 秒.".format(fail, css, time.time() - t1))
            self.take_screenshot()
            raise

    def js(self, script):
        """导入js"""
        t1 = time.time()
        try:
            self.driver.execute_script(script)
            time.sleep(3)
            # logging.info()("{0} 执行 js 脚本: {1}, 用时 {2:.2f} 秒.".format(success, script, time.time() - t1),level=1)
            logging.info("{0} 执行 js 脚本, 用时 {1:.2f} 秒.".format(success, time.time() - t1))
            return self
        except Exception:
            # logging.info()("{0} 无法执行 js 脚本: {1}, 用时 {2:.2f} 秒.".format(fail, script, time.time() - t1,level=1))
            logging.error("{0} 无法执行 js 脚本, 用时 {1:.2f} 秒.".format(success, time.time() - t1))
            raise

    def clear(self, css):
        """清除默认内容"""

        t1 = time.time()
        try:
            self.element_wait(css)
            self.el = self.get_element(css)
            self.el.clear()
            logging.info("{0} 清除元素: <{1}> , 用时 {2:.2f} 秒.".format(success, css, time.time() - t1))
            return self
        except Exception:
            logging.error("{0} 无法清除元素: <{1}> , 用时 {2:.2f} 秒.".format(fail, css, time.time() - t1))
            raise

    def clear_input(self, css, text):
        """清除默认内容，并输入新内容"""

        t1 = time.time()
        try:
            self.element_wait(css)

            self.el = self.get_element(css)
            self.el.clear()
            self.el.send_keys(text)

            logging.info("{0} 清除元素: <{1}> 输入: {2}, 用时 {3:.2f} 秒.".format(success, css, text, time.time() - t1))
            return self
        except Exception:
            logging.error("{0} 无法清除元素: <{1}> 输入: {2}, 用时 {3:.2f} 秒.".format(fail, css, text, time.time() - t1))
            raise

    def switch_to_frame(self, css):
        """frame切换"""
        t1 = time.time()
        try:
            self.element_wait(css)
            iframe_el = self.get_element(css)
            self.driver.switch_to.frame(iframe_el)
            logging.info("{0} 切换至iframe: <{1}>, 用时 {2:.2f} 秒".format(success, css, time.time() - t1))
            return self
        except Exception:
            logging.error("{0} 未能切换至iframe: <{1}>, 用时 {2:.2f} 秒".format(fail, css, time.time() - t1))
            raise

    def switch_to_frame_out(self):
        """
        frame退出
        """
        t1 = time.time()
        self.driver.switch_to.default_content()
        logging.info("{0} 退出iframe, 用时 {1:.2f} 秒".format(success, time.time() - t1))

    def add_cookies(self, cookie):
        """

        :param cookie:  cookie dict
        :return:
        """
        t1 = time.time()
        self.driver.add_cookie(cookie)
        logging.info("{0} 添加cookies, 用时 {1:.2f} 秒".format(success, time.time() - t1))

    def deleteall_cookies(self):
        t1 = time.time()
        self.driver.delete_all_cookies()
        logging.info("{0} 清除cookies, 用时 {1:.2f} 秒".format(success, time.time() - t1))


def retry(times=3, wait_time=5):
    def _warpper(func):
        def warpper(*args, **kwargs):
            raise_info = None
            rnum = 0
            for i in range(times):
                rnum += 1
                try:
                    ret = func(*args, **kwargs)
                    if rnum > 1:
                        print('{0} 执行次数: {1}次, 成功'.format(success, rnum))
                    return ret
                except Exception as ex:
                    time.sleep(wait_time)
                    raise_info = ex
            print('{0} 执行次数: {1}次, 全部失败'.format(fail, rnum))
            raise raise_info

        return warpper

    return _warpper

if __name__ == "__main__":
    from selenium.webdriver.common.by import By

    loc = (By.XPATH, '//*[@id="sb_form_q"]')
    loc2 =(By.XPATH,'//div[@data-sbtip="搜索网页"]')
    dr = pyselenium(123)
    dr.open("https://cn.bing.com/")
    dr.clear(loc).input(loc, "123")
    dr.click(loc2)